package com.example.springstudy.service.pay;

import com.example.springstudy.dao.req.WeChatPayReq;
import com.example.springstudy.dao.res.WeChatPayRes;
import com.example.springstudy.entity.Sku;
import com.example.springstudy.utils.RequestUtils;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.http.*;
import com.wechat.pay.java.core.util.GsonUtil;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.nativepay.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;

import java.lang.reflect.Field;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class WeChatPaymentService{

    /** 商户号 */
    public static String merchantId = "190000****";
    /** 商户API私钥路径 */
    public static String privateKeyPath = "/Users/yourname/your/path/apiclient_key.pem";
    /** 商户证书序列号 */
    public static String merchantSerialNumber = "5157F09EFDC096DE15EBE81A47057A72********";
    /** 商户APIV3密钥 */
    public static String apiV3Key = "...";

    private static Config config;
    private static NativePayService service;

    public static WeChatPaymentService builder(){
        buildService();
        return new WeChatPaymentService();
    }

    private static NativePayService buildService(){
        if(config == null){
            config = new RSAAutoCertificateConfig.Builder()
                    .merchantId(merchantId)
                    .privateKeyFromPath(privateKeyPath)
                    .merchantSerialNumber(merchantSerialNumber)
                    .apiV3Key(apiV3Key)
                    .build();
        }
        if(service == null){
            service = new NativePayService.Builder().config(config).build();
        }
        return service;
    }

    public void nativePay(String authCode) {
        // request.setXxx(val)设置所需参数，具体参数可见Request定义
        service = buildService();
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(1);
        request.setAmount(amount);
        request.setAppid("wxa9d9651ae******");
        request.setMchid("190000****");
        request.setDescription("测试商品标题");
        request.setNotifyUrl("https://notify_url");
        request.setOutTradeNo("out_trade_no_001");

        // 调用下单方法，得到应答
        PrepayResponse response = service.prepay(request);
        // 使用微信扫描 code_url 对应的二维码，即可体验Native支付
        System.out.println(response.getCodeUrl());
    }

    public void queryPayOrder() {
        service = buildService();
        QueryOrderByIdRequest queryRequest = new QueryOrderByIdRequest();
        queryRequest.setMchid("190000****");
        queryRequest.setTransactionId("4200001569202208304701234567");
        try {
            Transaction result = service.queryOrderById(queryRequest);
            System.out.println(result.getTradeState());
        } catch (ServiceException e) {
            // API返回失败, 例如ORDER_NOT_EXISTS
            System.out.printf("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            System.out.printf("reponse body=[%s]\n", e.getResponseBody());
        }
    }

    public void closePayOrder(){
        service = buildService();
        CloseOrderRequest closeRequest = new CloseOrderRequest();
        closeRequest.setMchid("190000****");
        closeRequest.setOutTradeNo("out_trade_no_001");
        // 方法没有返回值，意味着成功时API返回204 No Content
        service.closeOrder(closeRequest);
    }

    public static boolean moniPay(String code, String orderNo, String totalFee){

        return false;
    }

    public static WeChatPayRes scanPay(String code, String orderNo, String totalFee) throws IllegalAccessException {
        Config config = new RSAAutoCertificateConfig.Builder()
                .merchantId(merchantId)
                .privateKeyFromPath(privateKeyPath)
                .merchantSerialNumber(merchantSerialNumber)
                .apiV3Key(apiV3Key)
                .build();
        HttpClient client = new DefaultHttpClientBuilder().config(config).build();
        String requestPath = "https://api.mch.weixin.qq.com/pay/micropay"; //付款码支付

        WeChatPayReq request = new WeChatPayReq();
        request.setAuthCode(code);

        request.setOutTradeNo(orderNo);
        request.setTotalFee(totalFee);
        request.setMchId(merchantId);
        request.setNonceStr(generateNonceStr(16));
        request.setSpbillCreateIp(RequestUtils.getIp());
        request.setBody("史坨坨铺子-首饰");
        request.setAppId("wxa9d9651ae******");


        request.setSign(md5Signature(request));

        HostName hostName = null;
        if (hostName != null) {
            requestPath = requestPath.replaceFirst(HostName.API.getValue(), hostName.getValue());
        }

        HttpHeaders headers = new HttpHeaders();
        headers.addHeader("Accept", MediaType.APPLICATION_JSON.getValue());
        headers.addHeader("Content-Type", MediaType.APPLICATION_JSON.getValue());
        RequestBody body = (new JsonRequestBody.Builder()).body(GsonUtil.toJson(request)).build();
        HttpRequest httpRequest = (new HttpRequest.Builder()).httpMethod(HttpMethod.POST).url(requestPath).headers(headers).body(body).build();
        HttpResponse<WeChatPayRes> response = client.execute(httpRequest, WeChatPayRes.class);
        return response.getServiceResponse();
    }

    public static String generateNonceStr(int length) {
        // 定义随机字符串的字符集，可包含数字、大小写字母等
        String characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        Random random = new Random();
        StringBuilder nonceStr = new StringBuilder();

        // 生成一个长度在32位以内的随机字符串，这里示例生成16位
        for (int i = 0; i < length; i++) {
            int index = random.nextInt(characters.length());
            nonceStr.append(characters.charAt(index));
        }

        return nonceStr.toString();
    }

    public static Map<String, Object> convertObjectToMap(Object obj) throws IllegalAccessException {
        Map<String, Object> map = new HashMap<>();
        Class<?> clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            map.put(field.getName(), field.get(obj));
        }
        return map;
    }

    public static String convertObjectToSortedString(Object req) throws IllegalAccessException {

        Map<String, Object> parameters = convertObjectToMap(req);

        // 将Map的键值对转换为List<Map.Entry<String, Object>>，以便进行排序
        List<Map.Entry<String, Object>> entryList = new ArrayList<>(parameters.entrySet());

        // 按照键的ASCII字典序进行排序
        entryList.sort(Map.Entry.comparingByKey());

        // 使用流将排序后的键值对拼接成字符串，格式为key=value，并用&连接
        return entryList.stream()
                .map(entry -> entry.getKey() + "=" + entry.getValue())
                .collect(Collectors.joining("&"));
    }

    public static String md5Signature(WeChatPayReq request) throws IllegalAccessException {
        String input = convertObjectToSortedString(request);
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] messageDigest = md.digest(input.getBytes(StandardCharsets.UTF_8));
            BigInteger no = new BigInteger(1, messageDigest);
            StringBuilder hashText = new StringBuilder(no.toString(16));
            while (hashText.length() < 32) {
                hashText.insert(0, "0");
            }
            return hashText.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5算法不可用", e);
        }
    }


}
